package tests.mocks;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import com.lanchita.AerolineaLanchita;
import com.lanchita.excepciones.CodigoErroneoException;
import com.lanchita.excepciones.EstadoErroneoException;

public class AerolineaLanchitaMock extends AerolineaLanchita {

	private static final AerolineaLanchitaMock INSTANCE = new AerolineaLanchitaMock();

	private String[][] asientos;

	// ****************************************************************
	// ** STATICS
	// ****************************************************************

	public static AerolineaLanchita getInstance() {
		return INSTANCE;
	}

	// ****************************************************************
	// ** CONSTRUCTORS
	// ****************************************************************

	private AerolineaLanchitaMock() {
		this.setAsientos(new String[][] {
				{ "01202022220203-3", "159.90", "PRIMERACLASE", "VENTANA", "DISPONIBLE", "", "14:00","22:25","ARG","URU","16/08/2012","17/08/2012" },
				{ "01202022256566-3", "282.19", "TURISTA", "CENTRO", "DISPONIBLE", "", "23:25","22:00","URU","BRA","17/08/2012","18/08/2012" },
				{ "01202022220204-3", "159.90", "PRIMERACLASE", "VENTANA", "DISPONIBLE", "", "14:00","22:25","ARG","PAR","16/08/2012","17/08/2012" },
				{ "01202022256565-3", "282.19", "TURISTA", "CENTRO", "DISPONIBLE", "", "23:55","22:00","PAR","URU","17/08/2012","18/08/2012" },
//				{ "01202022220202-3", "159.90", "PRIMERACLASE", "VENTANA", "DISPONIBLE", "", "14:00","02:25","EZE","USA","16/08/2012","17/08/2012" },
				{ "01202022267867-7", "255.98", "EJECUTIVA", "PASILLO", "DISPONIBLE", "", "05:00","21:00","EZE","PER","16/08/2012","17/08/2012" },
				{ "01202022220008-3", "383.22", "TURISTA", "VENTANA", "DISPONIBLE", "", "22:00","23:00","PER","USA","17/08/2012","18/08/2012" },
				{ "01202022256565-3", "282.19", "TURISTA", "CENTRO", "DISPONIBLE", "", "20:00","22:00","EZE","AEO","16/08/2012","17/08/2012" },
				{ "01202022323423-5", "431.28", "TURISTA", "CENTRO", "DISPONIBLE", "", "23:00","18:00","AEO","USA","17/08/2012","18/08/2012"} });
//				{ "01202022220298-2", "528.81", "PRIMERACLASE", "VENTANA", "DISPONIBLE", "", "07:00","08:00","AEO","USH","16/08/2012","17/08/2012"} });
	}

	public AerolineaLanchitaMock(String[][] asientosRecibidos) {
		this.setAsientos(asientosRecibidos);
	}

	// ****************************************************************
	// ** QUERIES
	// ****************************************************************

	/**
	 * 
	 * Retorna el conjunto de los asientos disponibles para ir del origen al
	 * destino en la fecha solicitada. Los asientos devueltos estan
	 * representados por un array de Strings con la siguiente distribucion: <br>
	 * [0]: Codigo identificador del asiento. <br>
	 * [1]: Precio base del asiento. <br>
	 * [2]: Clase del asiento. Los valores pueden ser "P" para Primera, "E" para
	 * Ejecutivo y "C" para Turista. <br>
	 * [3]: Ubicacion del asiento. Los valores pueden ser "V" para Ventana, "C"
	 * para Centro y "P" para Pasillo. <br>
	 * [4]: Estado del asiento. Los valores pueden ser "D" para Disponible, "R"
	 * para Reservado y "C" para Comprado. En esta consulta solo se devolveran
	 * asientos "D". <br>
	 * [5]: DNI del cliente que reservo o compro el asiento. En esta consulta
	 * vendra siempre vacio. <br>
	 * [6]: horario de salida del vuelo con el formato hh:mm. <br>
	 * [7]: horario de llegada del vuelo con el formato hh:mm. <br>
	 * [8]: origen del vuelo<br>
	 * [9]: destino del vuelo<br>
	 * [10]: fecha de salida del vuelo con el formato dd/mm/aaaa<br>
	 * [11]: fecha de llegada del vuelo con el formato dd/mm/aaaa<br>
	 * 
	 * @param origen
	 *            Identificador del lugar de origen
	 * @param destino
	 *            Identificador del lugar de destino
	 * @param fecha
	 *            Fecha en la que se realizara el viaje
	 * 
	 * @return Array con asientos disponibles para ser reservados o comprados.
	 */
	public String[][] asientosDisponibles(String origen, String destino,
			String fechaSalida, String fechaLlegada, String horaSalida,
			String horaLlegada) {

		List<String[]> disponibles = Arrays.asList(this.getAsientos());
		List<String[]> retVal = new ArrayList<String[]>();
		Iterator<String[]> iterator = disponibles.iterator();
		
		boolean agregar;
		while (iterator.hasNext()) {
			String[] element = iterator.next();
			agregar = true;
			if (!element[4].equals("DISPONIBLE")) {
				agregar = false;
			}
			if(horaSalida!=null && !horarioValido(horaSalida,element[6])){
				agregar = false;
			}
			if(origen!=null && !element[8].equalsIgnoreCase(origen)){
				agregar = false;
			}
			if(destino!=null && !element[9].equalsIgnoreCase(destino)){
				agregar = false;
			}
			
			if(agregar){
				retVal.add(element);
			}
		}

		return retVal.toArray(new String[][] {});
	}
	//define si la hora de partida maxima tolerada es mayor a la hora de salida de un asiento 
	private boolean horarioValido(String horaSalidaMaxima, String horaSalidaAsiento) {
		
		return horaSalidaMaxima.compareTo(horaSalidaAsiento)>=0; 
		 
		
	}
	
	//define si el horario de un asiento esta entre la fecha de salida y entrada
	@SuppressWarnings("unused")
	private boolean estaEntre(String hora, String[] element) {
		String horaDeSalida = element[6];
		String horaDeLLegada = element[7];
		boolean mayorOigualQueHoraDeSalida = horaDeSalida.compareTo(hora)<0; 
		boolean menorOIgualQueHoraDeLLegada = horaDeLLegada.compareTo(hora)>0; 
		 
		return mayorOigualQueHoraDeSalida && menorOIgualQueHoraDeLLegada;
		
	}

	protected int getIndiceDeAsiento(String codigo) {
		for (int i = 0; i < this.getAsientos().length; i++) {
			if (this.getAsientos()[i][0].equals(codigo)) {
				return i;
			}
		}

		throw new CodigoErroneoException(codigo);
	}

	// ****************************************************************
	// ** OPERATIONS
	// ****************************************************************

	/**
	 * Realiza la compra del asiento con el código especificado.
	 * 
	 * @param codigo
	 *            Código identificador del asiento a comprar.
	 * 
	 * @throws CodigoErroneoException
	 *             si el código recibido no existe.
	 * @throws EstadoErroneoException
	 *             si se intenta comprar un asiento ya comprado o reservado por
	 *             otra persona.
	 * 
	 */
	public void comprar(String codigo) {
		String[] asiento = this.getAsientos()[this.getIndiceDeAsiento(codigo)];

		if (asiento[4].equals("C") || asiento[4].equals("R")) {
			throw new EstadoErroneoException();
		}

		asiento[4] = "C";
	}

	/**
	 * Realiza la reserva del asiento con el código especificado y lo vincula al
	 * dni recibido.
	 * 
	 * @param codigo
	 *            Código identificador del asiento a reservar.
	 * @param dni
	 *            DNI del comprador.
	 * 
	 * @throws CodigoErroneoException
	 *             si el código recibido no existe.
	 * @throws EstadoErroneoException
	 *             si se intenta reservar un asiento que no está disponible.
	 * 
	 */
	public void reservar(String codigo, String dni) {
		String[] asiento = this.getAsientos()[this.getIndiceDeAsiento(codigo)];

		if (!asiento[4].equals("D")) {
			throw new EstadoErroneoException();
		}

		asiento[4] = "R";
	}

	// ****************************************************************
	// ** ACCESSORS
	// ****************************************************************

	protected String[][] getAsientos() {
		return this.asientos;
	}

	protected void setAsientos(String[][] asientos) {
		this.asientos = asientos;
	}
}
